package xworker.lang.task.flow;

import org.xmeta.ActionContext;
import org.xmeta.Thing;
import xworker.lang.executor.Executor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class TaskFlow {
    private static final String TAG = TaskFlow.class.getName();

    boolean started = false;
    boolean finished = false;

    Thing thing;

    ActionContext actionContext;

    /** 任务缓存*/
    final Map<String, TaskFlowTask> taskMap = new HashMap<>();

    /** 未准备好执行的任务列表　*/
    final List<TaskFlowTask> unreadyTasks = new ArrayList<>();

    final Object lockObj = new Object();

    public TaskFlow(Thing thing, ActionContext parentContext){
        this.thing = thing;
        this.actionContext = new ActionContext();
        Map<String, Object> variables = thing.doAction("getVariables", parentContext);
        if(variables != null){
            actionContext.putAll(variables);
        }

        actionContext.put("parentContext", parentContext);
        actionContext.put("taskFlow", this);
    }

    public TaskFlowTask getTask(String name){
        return taskMap.get(name);
    }

    public Thing getThing() {
        return thing;
    }

    public ActionContext getActionContext() {
        return actionContext;
    }

    public void fireTaskFinished(TaskFlowTask task){
        synchronized (lockObj){
            List<TaskFlowTask> nextTasks = task.getNextTasks();
            if(nextTasks != null){
                for(TaskFlowTask nextTask : nextTasks){
                    if(taskMap.get(nextTask.getName()) == null){
                        taskMap.put(nextTask.getName(), nextTask);
                    }else{
                        Executor.info(TAG, "Task already exists, don not start, taskName=" + nextTask.getName()
                                + ", parentTask=" + task.getName() + ", taskFlow=" + thing.getMetadata().getPath());
                    }
                }
            }

            //检查状态，是否有等待的任务可以启动等
            checkTasks();

            //检查是否存在正在执行的任务，如果存在
            boolean allFinished = true;
            for(String key : taskMap.keySet()){
                TaskFlowTask theTask = taskMap.get(key);
                if(!theTask.isFinished()){
                    allFinished = false;
                    break;
                }
            }

            finished = allFinished;

            //触发事件
            thing.doAction("onTaskFinished", actionContext, "task", task);
        }
    }

    public void cancel(){
        synchronized (lockObj){
            for(String key : taskMap.keySet()){
                taskMap.get(key).cancel();
            }

            started = false;
        }

        thing.doAction("onCanceled", actionContext, "taskFlow", this);
    }

    public void start(){
        if(started){
            Executor.info(TAG, "TaskFlow is started, do not need start again. path=" + thing.getMetadata().getPath());
            return;
        }

        started = true;
        //先清空
        taskMap.clear();

        //加入任务
        for(Thing taskThing : thing.getChilds("TaskFlowTask")){
            TaskFlowTask task = new TaskFlowTask(taskThing, this);
            taskMap.put(task.getName(), task);
        }

        //检查和启动任务
        checkTasks();

        thing.doAction("onStarted", actionContext, "taskFlow", this);
    }

    public List<TaskFlowTask> getRunningTasks(){
        List<TaskFlowTask> tasks = new ArrayList<>();
        synchronized (lockObj){
            for(String key : taskMap.keySet()){
                TaskFlowTask task = taskMap.get(key);
                if(task.isStarted() && !task.isFinished()){
                    tasks.add(task);
                }
            }
        }

        return tasks;
    }

    public boolean hasRunningTasks(){
        return getRunningTasks().size() > 0;
    }

    /**
     * 检查未启动的任务，如果已经准备好，那么执行。
     */
    public void checkTasks(){
        synchronized (lockObj){
            for(String key : taskMap.keySet()){
                TaskFlowTask task = taskMap.get(key);

                if(!task.isStarted() && task.isReady()){
                    task.execute();
                }
            }
        }
    }

    /**
     * 添加任务实例。
     */
    public void addTask(TaskFlowTask task){
        taskMap.put(task.getName(), task);
        if(task.isReady()){
            task.execute();
        }else{
            unreadyTasks.add(task);
        }
    }

    public static TaskFlow getTaskFlow(Thing thing, ActionContext actionContext){
        TaskFlow taskFlow = thing.getStaticData("taskFlow");
        if(taskFlow == null){
            taskFlow = new TaskFlow(thing, actionContext);
            thing.setStaticData("taskFlow", taskFlow);
        }

        return taskFlow;
    }
}
